package cn.cj.erp.serviceimpl.system;

import cn.cj.erp.common.constants.SystemConstants;
import cn.cj.erp.common.utils.Convert;
import cn.cj.erp.bo.system.SysMenuBo;
import cn.cj.erp.service.system.SysMenuService;
import cn.cj.erp.service.system.SysRoleMenuService;
import cn.cj.erp.serviceimpl.base.ServiceImpl;
import cn.cj.erp.common.exception.ServiceException;
import cn.cj.erp.entity.system.SysMenu;
import cn.cj.erp.dao.system.SysMenuDao;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * 菜单
 *
 * @author chenjian
 */
@Slf4j
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenu, SysMenuBo> implements SysMenuService {
    @Resource
    private SysMenuDao sysMenuDao;
    @Resource
    private SysRoleMenuService sysRoleMenuService;

    @Override
    public SysMenuDao getBaseMapper() {
        return sysMenuDao;
    }


    @Override
    public SysMenu convert2Entity(SysMenuBo sysMenuBo) {
        return Convert.convert(sysMenuBo, SysMenu.class);
    }

    @Override
    public SysMenuBo convert2Bo(SysMenu sysMenu) {
        return Convert.convert(sysMenu, SysMenuBo.class);
    }

    @Override
    public List<SysMenuBo> queryTree(SysMenuBo params) {
        Long treeRootId = params.getTreeRootId();
        if (treeRootId == null) {
            treeRootId = SystemConstants.TREE_ROOT;
        }
        if (SystemConstants.SUPER_ADMIN.equals(params.getUserId())) {
            params.setUserId(null);
        }
        List<SysMenuBo> menus = super.queryList(params);
        return buildTree(menus, treeRootId);
    }

    /**
     * 根据父ID查找子菜单的数量
     *
     * @param parentId 父ID
     * @return Integer
     */
    @Override
    public Integer countByParentId(Long parentId) {
        return lambdaQuery().eq(SysMenu::getParentId, parentId).count();
    }

    @Override
    public Integer getCurrentUsedOrderNum(Long parentId) {
        Integer sort = getBaseMapper().getMaxOrderNum(parentId);
        if (sort == null) {
            sort = 1;
        }
        return sort + 1;
    }

    @Override
    public boolean removeById(Long id) {
        if (this.existChild(id)) {
            throw new ServiceException("存在子菜单,不允许删除");
        }
        if (sysRoleMenuService.existByMenuId(id)) {
            throw new ServiceException("菜单已分配给角色,不允许删除");
        }
        //删除菜单
        return super.removeById(id);
    }

    @Override
    public boolean existChild(Long menuId) {
        return lambdaQuery().eq(SysMenu::getParentId, menuId).count() > 0;
    }

    /**
     * 检验名称是否唯一
     * @param bo 实体类
     * @return Boolean>
     */
    @Override
    public boolean existName(SysMenuBo bo) {
        return lambdaQuery()
                .ne(bo.getMenuId() != null, SysMenu::getMenuId, bo.getMenuId())
                .eq(SysMenu::getMenuName, bo.getMenuName())
                .count() > 0;
    }

    @Override
    public boolean existCode(SysMenuBo bo) {
        return lambdaQuery()
                .ne(bo.getMenuId() != null, SysMenu::getMenuId, bo.getMenuId())
                .eq(SysMenu::getMenuCode, bo.getMenuCode())
                .count() > 0;
    }


    // ----------------------------------------------------------------
    /**
     * 构建菜单树
     *
     * @param list 菜单列表（此时还不是树，仅仅是一个列表）
     * @param parentId 传入的父节点ID
     * @return 构建好的菜单树
     */
    public List<SysMenuBo> buildTree(List<SysMenuBo> list, Long parentId) {
        List<SysMenuBo> returnList = new ArrayList<>();
        for (SysMenuBo t : list) {
            // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点
            if (parentId.equals(t.getParentId())) {
                recursionFn(list, t);
                returnList.add(t);
            }
        }
        if (returnList.isEmpty()) {
            returnList = list;
        }
        return returnList;
    }

    /**
     * 递归构建菜单树
     *
     * @param list 分类表
     * @param t 子节点
     */
    private void recursionFn(List<SysMenuBo> list, SysMenuBo t) {
        // 得到子节点列表
        List<SysMenuBo> childList = getChildList(list, t);
        t.setChildren(childList);
        for (SysMenuBo tChild : childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild);
            }
        }
    }

    /**
     * 从列表中获取parent的所有子菜单
     * @param list 菜单列表
     * @param parent 父菜单
     * @return parent的直属子菜单
     */
    private List<SysMenuBo> getChildList(List<SysMenuBo> list, SysMenuBo parent) {
        List<SysMenuBo> tList = new ArrayList<>();
        for (SysMenuBo n : list) {
            if (n.getParentId().equals(parent.getMenuId())) {
                tList.add(n);
            }
        }
        return tList;
    }

    /**
     * 判断是否有子菜单
     * @param list 菜单列表
     * @param parent 父菜单
     * @return true-有子菜单，false-无子菜单
     */
    private boolean hasChild(List<SysMenuBo> list, SysMenuBo parent) {
        return getChildList(list, parent).size() > 0;
    }

}
